package com.honeybee.cloud.framework.common.http;

import cn.hutool.core.util.CharsetUtil;
import cn.hutool.http.ContentType;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.honeybee.cloud.framework.base.exception.business.BaseBizException;
import com.honeybee.cloud.framework.base.exception.business.BaseBizExceptionEnum;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.http.Consts;
import org.apache.http.HttpEntity;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.*;
import org.apache.http.cookie.Cookie;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.message.BasicHeader;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.springframework.context.annotation.Bean;
import org.springframework.util.Assert;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

@Slf4j
@Data
@SuppressWarnings("all")
public class HttpClient {

    /**
     * http
     * 发送HttpGet请求
     *
     * @param url
     * @return
     */
    public String sendGet(BasicCookieStore cookieStore, String url, Object params, Map<String, String> headers) throws Exception {
        Assert.notNull(url, "url not null");
        HttpGet httpget = new HttpGet(url);
        CloseableHttpResponse response = null;
        try {
            Map<String, String> paramsMap = BeanUtils.describe(params);
            url = buildUrl(url, paramsMap);
            if (Objects.nonNull(headers)) {
                headers.forEach((key, value) -> {
                    httpget.addHeader(new BasicHeader(key, value));
                });
            }
            log.info("http url:{}", httpget.getURI().toString());
            log.info("http header:{}", JSONArray.toJSONString(httpget.getAllHeaders()));
            response = getHttpClient(cookieStore).execute(httpget);
            log.info("http status:{}", response.getStatusLine().getStatusCode());
            String result = null;
            if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                HttpEntity entity = response.getEntity();
                result = EntityUtils.toString(entity);
                log.info("http result:{}", result);
                return result;
            } else {
                throw BaseBizException.getInstance(BaseBizExceptionEnum.HTTP_REQUEST_EXP);
            }

        } finally {
            if (Objects.nonNull(httpget)) {
                httpget.releaseConnection();
            }

            if (Objects.nonNull(response)) {
                response.close();
            }
        }


    }

    /**
     * 发送HttpGet请求
     *
     * @param url
     * @return
     */
    public String sendGet(BasicCookieStore cookieStore, String url, Map<String, String> headers) throws Exception {
        return sendGet(cookieStore, url, null, headers);
    }

    /**
     * 发送HttpGet请求
     *
     * @param url
     * @return
     */
    public String sendGet(String url, Object params, Map<String, String> headers) throws IOException {
        return sendGet(url, params, headers);
    }

    /**
     * 发送HttpGet请求
     *
     * @param url
     * @return
     */
    public String sendGet(String url, Map<String, String> headers) throws IOException {
        return sendGet(url, null, headers);
    }

    /**
     * 发送HttpGet请求
     *
     * @param url
     * @return
     */
    public String sendGet(String url, Object params) throws IOException {
        return sendGet(null, params, null);
    }

    /**
     * 发送HttpGet请求
     *
     * @param url
     * @return
     */
    public String sendGet(String url) throws Exception {
        return sendGet(null, url, null, null);
    }

    public String sendPage(BasicCookieStore cookieStore, String url, Object params, Map<String, String> headers) throws Exception {
        CloseableHttpResponse response = null;
        HttpUriRequest uriRequest = null;
        try {
            Assert.notNull(url, "url not null");
            Map<String, String> paramsMap = BeanUtils.describe(params);
            url = buildUrl(url, paramsMap);
            RequestBuilder builder = RequestBuilder.get().setUri(new URI(url));
            if (Objects.nonNull(headers)) {
                headers.forEach((key, value) -> {
                    builder.addHeader(new BasicHeader(key, value));
                    log.info("http header:{},{}", key,value);
                });
            }
            uriRequest = builder.build();
            log.info("http url:{}", uriRequest.getURI().toString());
            response = getHttpClient(cookieStore).execute(uriRequest);
            log.info("http status:{}", response.getStatusLine().getStatusCode());
            String result = null;
            if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                HttpEntity entity = response.getEntity();
                result = EntityUtils.toString(entity);
                return result;
            } else {
                throw BaseBizException.getInstance(BaseBizExceptionEnum.HTTP_REQUEST_EXP);
            }
        } finally {
            if (Objects.nonNull(uriRequest)) {
                uriRequest.abort();
            }
            if (Objects.nonNull(response)) {
                response.close();
            }
        }

    }

    public String sendPage(String url, Object params, Map<String, String> headers) throws Exception {
        return sendPage(url, params, headers);
    }

    public String sendPage(String url, Map<String, String> headers) throws Exception {
        return sendPage(url, null, headers);
    }

    public String sendPage(BasicCookieStore cookieStore, String url, Map<String, String> headers) throws Exception {
        return sendPage(cookieStore, url, null, headers);
    }

    public String sendPage(BasicCookieStore cookieStore, String url, Object params) throws Exception {
        return sendPage(cookieStore, url, params, null);
    }

    /**
     * 发送HttpPost请求，参数为map
     *
     * @param url
     * @param params
     * @return
     */
    public String sendForm(BasicCookieStore cookieStore, String url, Object params, Map<String, String> headers) throws Exception {
        Assert.notNull(url, "url not null");
        HttpPost httppost = new HttpPost(url);
        CloseableHttpResponse response = null;
        try {
            List<NameValuePair> formParams = new ArrayList<>();
            Map<String, String> paramMap = BeanUtils.describe(params);
            if (Objects.nonNull(paramMap)) {
                paramMap.forEach((key, value) -> {
                    formParams.add(new BasicNameValuePair(key, Objects.toString(value)));
                });
            }
            UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(formParams, Consts.UTF_8);
            if (Objects.nonNull(headers)) {
                headers.forEach((key, value) -> {
                    httppost.addHeader(new BasicHeader(key, value));
                    log.info("http header:{},{}", key,value);
                });
            }
            log.info("http url:{}", httppost.getURI().toString());
            log.info("http entity:{}", EntityUtils.toString(formEntity));
            httppost.setEntity(formEntity);
            response = getHttpClient(cookieStore).execute(httppost);
            log.info("http status:{}", response.getStatusLine().getStatusCode());
            HttpEntity httpEntity = response.getEntity();
            String result = null;
            if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                HttpEntity entity = response.getEntity();
                result = EntityUtils.toString(entity);
                log.info("http result:{}", result);
                return result;
            } else {
                throw BaseBizException.getInstance(BaseBizExceptionEnum.HTTP_REQUEST_EXP);
            }
        } finally {
            if (Objects.nonNull(httppost)) {
                httppost.releaseConnection();
            }
            if (Objects.nonNull(response)) {
                response.close();
            }
        }

    }

    /**
     * post请求
     *
     * @param url
     * @param json
     * @return
     */
    public String sendJson(String url, Map<String, String> headers, String json) throws Exception {
        Assert.notNull(url, "url not null");
        HttpPost httppost = new HttpPost(url);
        CloseableHttpResponse response = null;
        try {
            if (Objects.nonNull(headers)) {
                headers.forEach((key, value) -> {
                    httppost.addHeader(new BasicHeader(key, value));
                    log.info("http header:{},{}", key,value);
                });
            }
            StringEntity s = new StringEntity(json, CharsetUtil.UTF_8);
            log.info("http url:{}", httppost.getURI().toString());
            log.info("http entity:{}", EntityUtils.toString(s));
            s.setContentEncoding(CharsetUtil.UTF_8);
            s.setContentType(ContentType.JSON.name());
            httppost.setEntity(s);
            response = getHttpClient().execute(httppost);
            log.info("http status:{}", response.getStatusLine().getStatusCode());
            HttpEntity httpEntity = response.getEntity();
            HttpEntity entity = response.getEntity();
            String result = EntityUtils.toString(entity);
            log.info("http result:{}", result);
            return result;
        } finally {
            if (Objects.nonNull(httppost)) {
                httppost.releaseConnection();
            }
            if (Objects.nonNull(response)) {
                response.close();
            }
        }


    }

    /**
     * post请求
     *
     * @param url
     * @param json
     * @return
     */
    public String sendJson(String url, String json) throws Exception {
        return sendJson(url, null, json);

    }

    /**
     * 发送不带参数的HttpPost请求
     *
     * @param url
     * @return
     */
    public String sendForm(String url) throws Exception {
        return sendForm(null, url, null, null);
    }

    /**
     * 发送不带参数的HttpPost请求
     *
     * @param url
     * @return
     */
    public String sendForm(String url, Map<String, String> headers) throws Exception {
        return sendForm(null, url, null, headers);
    }

    /**
     * 发送不带参数的HttpPost请求
     *
     * @param url
     * @return
     */
    public String sendForm(String url, Object params) throws Exception {
        return sendForm(null, url, params, null);
    }

    public String sendForm(BasicCookieStore cookieStore, String url, Map<String, String> headers) throws Exception {
        return sendForm(cookieStore, url, null, headers);
    }

    /**
     * 发送不带参数的HttpPost请求
     *
     * @param url
     * @return
     */
    public String sendForm(BasicCookieStore cookieStore, String url, Object params) throws Exception {
        return sendForm(cookieStore, url, params, null);
    }

    /**
     * url append param
     *
     * @param url
     * @param querys
     * @return
     * @throws UnsupportedEncodingException
     */
    private String buildUrl(String url, Map<String, String> querys) throws UnsupportedEncodingException {
        Assert.notNull(url, "url not null");
        StringBuilder sbUrl = new StringBuilder(url);
        StringBuilder sbQuery = new StringBuilder();
        if (MapUtils.isNotEmpty(querys)) {
            querys.forEach((key, value) -> {
                try {
                    sbQuery.append(key).append("=").append(URLEncoder.encode(value, "utf-8")).append("&");
                } catch (Exception e) {
                    log.error(e.getMessage(), e);
                }
            });
            if (!url.contains("?")) {
                sbUrl.append("?");
            } else {
                sbUrl.append("&");
            }
            sbUrl.append(sbQuery);
        }
        return sbUrl.toString();
    }

    private CloseableHttpClient getHttpClient() throws Exception {
        return getHttpClient(null);
    }

    @Bean
    public CloseableHttpClient getHttpClient(BasicCookieStore cookieStore) throws Exception {
        CloseableHttpClient httpClient = null;
        HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
        if (Objects.nonNull(cookieStore)) {
            httpClientBuilder.setDefaultCookieStore(cookieStore);
            for (Cookie cookie : cookieStore.getCookies()) {
                log.info("http cookie:{}", JSONObject.toJSONString(cookie));
            }
        }

        httpClient = httpClientBuilder.setConnectionTimeToLive(9L, TimeUnit.SECONDS).setMaxConnPerRoute(9).setMaxConnTotal(9).build();
        return httpClient;
    }


}
